﻿using UnityEngine;
using UnityEngine.UIElements;

namespace winS.UnityEditor.UIElement
{
    /// <summary>
    /// 垂直滚动视图
    /// </summary>
    public class VerticalScrollView : VisualElement
    {
        /// <summary>
        /// 默认滚动间隔
        /// </summary>
        public static readonly float defaultScrollDelta = 18f;

        /// <summary>
        /// 滚动增量
        /// </summary>
        public float scrollDelta { get; set; } = defaultScrollDelta;

        public override VisualElement contentContainer { get; }

        protected readonly VisualElement mask;
        protected readonly VerticalScrollBar verticalScrollBar;

        /// <summary>
        /// 内容高度
        /// </summary>
        private float contentHeight => contentContainer.layout.height;

        /// <summary>
        /// 内容视图最大偏移
        /// </summary>
        private float maxOffset;
        /// <summary>
        /// 内容视图当前偏移
        /// </summary>
        private float currentOffset;
        /// <summary>
        /// 垂直滚动条可滚动的距离
        /// </summary>
        private float verticalScrollBarDistance;
        /// <summary>
        /// 内容视图偏移百分比
        /// </summary>
        private float offsetPercent => currentOffset / maxOffset;

        private bool verticalScrollBarShowing;

        internal VerticalScrollView()
        {
            hierarchy.Add(mask = EditorElementUtility.elementFactory.CreateEditorElementWithName("内容遮罩"));
            mask.style.overflow = Overflow.Hidden;

            mask.Add(contentContainer = EditorElementUtility.elementFactory.CreateEditorElementWithName("内容容器"));
            contentContainer.style.flexShrink = 0f;

            hierarchy.Add(verticalScrollBar = new VerticalScrollBar());


            RegisterCallback<WheelEvent>(WheelCallback);
            RegisterCallback<GeometryChangedEvent>(GeometryChangedCallback);
        }

        private void ShowVerticalScrollBar(float viewportHeight)
        {
            verticalScrollBarShowing = true;
            float percent = viewportHeight / contentHeight;//视口在内容中所占百分比
            float scrollBarHeight = percent * viewportHeight;//滚动条高度
            verticalScrollBar.SetHeight(scrollBarHeight);
            verticalScrollBarDistance = viewportHeight - scrollBarHeight;//垂直滚动条可移动的距离
            maxOffset = contentHeight - viewportHeight;

            float newPosition = offsetPercent * verticalScrollBarDistance;//滚动条新位置

            //滚动条在新位置下剩余可用的高度
            float remainingHeight = viewportHeight - newPosition;
            if (scrollBarHeight < remainingHeight)//新高度未超过剩余可用高度
            {
                verticalScrollBar.position = newPosition;
                return;
            }
            //新高度超过了剩余可用高度, 减少内容偏移
            float overflowHeight = scrollBarHeight - remainingHeight;
            SetContentOffset(currentOffset - overflowHeight / viewportHeight * maxOffset);
        }
        private void HideVerticalScrollBar()
        {
            verticalScrollBarShowing = false;
            verticalScrollBar.SetHeight(0f);
        }

        private void WheelCallback(WheelEvent wheelEvent)
        {
            if (!verticalScrollBarShowing) return;
            float increment = wheelEvent.delta.y > 0f ? 1f : -1f;
            SetContentOffset(currentOffset + scrollDelta * increment);
        }

        private void SetContentOffset(float offset)
        {
            currentOffset = Mathf.Clamp(offset, 0f, maxOffset);
            contentContainer.style.top = -currentOffset;
            verticalScrollBar.position = offsetPercent * verticalScrollBarDistance;
        }
        private void GeometryChangedCallback(GeometryChangedEvent geometryChangedEvent)
        {
            float newHeight = geometryChangedEvent.newRect.height;
            if (newHeight < contentHeight) ShowVerticalScrollBar(newHeight);
            else HideVerticalScrollBar();
        }
    }
}